home *** CD-ROM | disk | FTP | other *** search
- /*
- File: OTLLCTest.c
-
- Contains: Simple app write or receive 8022 Ethernet packets using a multicast address
- This program implements both a sender and receiver such that both sides
- open an 802.2 Ethernet endpoint. The user can then select whether to run the
- program as a sender or receiver. If implemented as a receiver, the endpoint
- is bound, and the multicast option is turned on. The receiver waits in a
- spin loop for a specified period of time before quitting. The receiver will process
- all incoming ethernet packets destined to the endpoint for the specified
- protocol. Upon receipt, the program checks to see whether the packet was sequential
- to the previous packet. A collection of global counter maintains the number of
- inOrder, outOfOrder packets, and the number of packets reads resulting in an error,
- plus the number of packets which come in back to back while in the handler.
-
- Note the this sample turns on the rawmode option so that the handler will be passed the
- 14 byte 802.2 header.
- Also note that the sender may also implement the rawmode option so that it can also
- fill in the header bytes itself. If this is done, then the buffer needs to
- be enlarged to include these additional bytes. These additional bytes will not affect
- the maximum tsdu size since the tsdu size is the i-frame limit and does not include
- the header size.
-
- The sender process, sends 10005 x 1500 byte packets as fast as possible. The user
- can select to to turn on AckSends mode where the packet is handed to OT and not
-
- released until OT sends the information to the lower layer.
- Written by: Rich Kubota
-
- Copyright: Copyright © 1993-1999 by Apple Computer, Inc., All Rights Reserved.
-
- You may incorporate this Apple sample source code into your program(s) without
- restriction. This Apple sample source code has been provided "AS IS" and the
- responsibility for its operation is yours. You are not permitted to redistribute
- this Apple sample source code as "Apple sample source code" after having made
- changes. If you're going to re-distribute the source, we require that you make
- it clear in the source that the code was descended from Apple sample source
- code, but that you've made changes.
-
- Change History (most recent first):
- 7/22/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1
- 01/98 added threshold timer to control how often WNE gets called.
- 01/98 fixed sample so that you can send in raw mode and receive in
- regular mode or vice versa and things work.
- Fixed problem that when setting the max data packet size to
- 1500 bytes and are sending data in regular mode, adjust the
- unitdata.data.len field to account for the fact that the
- endpoint will insert the LLC header and the SNAP header.
- For raw mode, this is not an issue. Added feature to 1. allow
- the program to be re-used without having to quit 2. ask user for
- the drivername to use e.g. 'enet0, 'enet1', etc.,
- 01/98 modified the sample to use the revised NegotiateRawModeOption
- code which returns the template type. The Mentat template driver
- returns an additional 24 bytes of info at the beginning of the
- raw data packet.
- 01/98 modified DoBind so that one can use either a regular LLC to SNAP
- endpoint.
- 10/97 fixed bug in OT 8022 module which prevented more than 1483 data
- bytes from being sent in raw mode. Requires OT 1.3 to send > 1483
- data bytes with endpoint in rawdata mode.
-
- */
- #include <stdio.h>
- #include <Types.h>
- #include <Memory.h>
- #include <Resources.h>
- #include <Events.h>
- #include <OpenTransport.h> // open transport files
- #include <OpenTptLinks.h>
- #include <OpenTptAppleTalk.h>
- #include <OpenTptConfig.h>
- #include <Time.h>
- #include <Errors.h>
- #include <String.h>
- #include "OTLLCTest.h"
- #include "NegotiateRawModeSample.h"
-
- // Comment out the following line if synchronous sends desired.
- #define __ASYNCSEND__ 1
-
- //-----------------------------------------------------------------------------------------
- // Globals
- //-----------------------------------------------------------------------------------------
-
- EndpointRef gEndpoint;
- OSStatus gstatus;
- UInt32 gFlags;
- UInt32 gNumBack, gNumFore;
- UInt32 gPacketsRead;
- UInt32 gBackToBackPackets;
- UInt32 gInOrder;
- UInt32 gOutOfOrder;
- UInt32 gCounter;
- UInt32 gNumDataEvents;
- UInt32 gReadErrors;
- UInt32 gTemplateType;
- UInt32 gNumMemErrs;
- UInt32 gTimerThreshold;
- UInt8 *gBuffer;
- UInt8 *gDummyBuffer;
- struct T8022Address gAddr;
- UInt8 gmcAddr[k48BitAddrLength] = {MCASTADDR0,MCASTADDR1,MCASTADDR2,MCASTADDR3,MCASTADDR4,MCASTADDR5};
- PacketBuffer gPacket;
- UInt8 gFlag1;
- Boolean gDone;
- Boolean gAbort;
- //-----------------------------------------------------------------------------------------
- // Prototypes
- //-----------------------------------------------------------------------------------------
- extern OSStatus OTSetMemoryLimits(size_t growSize, size_t mazSize);
- OSStatus DoBind();
- OSStatus DoAddMulticast(EndpointRef ep, unsigned char *mcAddr);
- OSStatus DoRemoveMulticast(EndpointRef ep, unsigned char *mcAddr);
- void WriteApplIntro(void);
- UInt32 GetYesNoOption(void);
- UInt32 GetUserOption(void);
- Boolean CanDoMDATAMode(EndpointRef ep);
- void DoOTLLCWriteTest(void);
- Boolean DoSendPacket(EndpointRef ep);
- void DoOTLLCReadTest(void);
- OSStatus DoReadPacket(EndpointRef ep, UInt8 *mainBuffer);
- pascal void LLCEventHandler(void* ref, OTEventCode event, OTResult result, void* cookie);
- void CallWNE(void);
- void MyIdle(void);
- void DoValueBreak(long value, const char* message);
- void GetDriverName(char *name);
- void SetTimerThreshold(void);
- void PrintAppleTalkPortName(void);
- void ListEnetDrivers(void);
-
-
- /*******************************************************************************
- ** DoBindENET
- ********************************************************************************/
-
- OSStatus DoBind(void)
- {
- OSStatus osstatus;
- TBind requestInfo;
- TBind responseInfo;
- UInt32 i;
-
- gAddr.fAddrFamily = AF_8022;
-
- for (i = 0; i < k48BitAddrLength; i++)
- gAddr.fHWAddr[i] = 0x00;
-
- gAddr.fSAP = TESTSAP;
-
- if (TESTSAP == 0xAA)
- {
- // set SNAP fields;
-
- gAddr.fSNAP[0] = MYSNAP0; // set these values in the interface file OTLLCTest.h
- gAddr.fSNAP[1] = MYSNAP1;
- gAddr.fSNAP[2] = MYSNAP2;
- gAddr.fSNAP[3] = MYSNAP3;
- gAddr.fSNAP[4] = MYSNAP4;
-
- requestInfo.addr.len = k8022SNAPAddressLength;
- }
- else
- {
- requestInfo.addr.len = k8022BasicAddressLength;
- }
-
-
- // finish bind information
- requestInfo.addr.buf = (UInt8 *)&gAddr;
-
- requestInfo.addr.maxlen = 0;
- requestInfo.qlen = 0;
-
- responseInfo.addr.buf = (UInt8 *)&gAddr;
- responseInfo.addr.len = 0;
- responseInfo.addr.maxlen = k8022SNAPAddressLength;
- responseInfo.qlen = 0;
-
-
-
- osstatus = OTBind(gEndpoint, &requestInfo, &responseInfo);
- if (osstatus == kOTNoError)
- SetEPBoundFlag(gFlags);
-
- return osstatus;
- }
-
-
-
- /*******************************************************************************
- ** DoAddMulticast
- ********************************************************************************/
-
- OSStatus DoAddMulticast(EndpointRef ep, unsigned char *mcAddr)
- {
- OSStatus osstatus = noErr;
- TOptMgmt req;
- UInt8 reqOpt[64];
-
- req.opt.buf = reqOpt;
- req.flags = T_NEGOTIATE;
-
- ((TOption*)reqOpt)->level = LNK_TPI;
- ((TOption*)reqOpt)->name = OPT_ADDMCAST;
- ((TOption*)reqOpt)->len = kOTOptionHeaderSize + k48BitAddrLength;
- ((TOption*)reqOpt)->status = 0;
- memcpy(((TOption*)reqOpt)->value, mcAddr, k48BitAddrLength);
-
- req.opt.len = kOTOptionHeaderSize + k48BitAddrLength;
- req.opt.maxlen = sizeof(reqOpt);
-
- if ( (osstatus = OTOptionManagement(ep, &req, &req)) != kOTNoError )
- fprintf(stderr, "DoAddMulticast - OptionManagement Returned %d\n", osstatus);
- else
- {
- if (((TOption*)reqOpt)->status != T_SUCCESS)
-
- {
- fprintf(stderr, "DoAddMulticast - failed Status = %d\n", ((TOption*)reqOpt)->status);
- osstatus = -1;
- }
- else
- {
- fprintf(stderr, "DoAddMulticast - was successful\n");
- SetMCastActiveFlag(gFlags);
- }
- }
- return osstatus;
- }
-
-
- /*******************************************************************************
- ** DoRemoveMulticast
- ********************************************************************************/
-
- OSStatus DoRemoveMulticast(EndpointRef ep, unsigned char *mcAddr)
- {
- OSStatus osstatus = noErr;
- TOptMgmt req;
- UInt8 reqOpt[64];
-
- req.opt.buf = reqOpt;
- req.flags = T_NEGOTIATE;
-
- ((TOption*)reqOpt)->level = LNK_TPI;
- ((TOption*)reqOpt)->name = OPT_DELMCAST;
- ((TOption*)reqOpt)->status = 0;
- ((TOption*)reqOpt)->len = kOTOptionHeaderSize + k48BitAddrLength;
- memcpy(((TOption*)reqOpt)->value, mcAddr, k48BitAddrLength);
-
- req.opt.len = kOTOptionHeaderSize + k48BitAddrLength;
- req.opt.maxlen = sizeof(reqOpt);
-
- if ( (osstatus = OTOptionManagement(ep, &req, &req)) != kOTNoError )
- fprintf(stderr, "\nDoRemoveMulticast failed - OptionManagement Returned %d.", osstatus);
- else
- {
- if (((TOption*)reqOpt)->status != T_SUCCESS)
- {
- fprintf(stderr, "nDoRemoveMulticast - failed Status = %d\n", ((TOption*)reqOpt)->status);
- osstatus = -1;
- }
- else
- {
- fprintf(stderr, "nDoRemoveMulticast - was successful\n");
- SetMCastActiveFlag(gFlags);
- }
- }
-
- return osstatus;
- }
-
- void WriteApplIntro(void)
- {
- fprintf(stderr, "\nEthernet 802.2 LLC Test program v1.0\n");
- fprintf(stderr, "\nThis test application sets the system");
- fprintf(stderr, "\ninto send or receive mode.\n");
- fprintf(stderr, "\nThe send portion of this program sets the Ethernet");
- fprintf(stderr, "\ndriver to use a multicast address, then sends 10000");
- fprintf(stderr, "\n- 1500 byte packets out the wire.\n");
- fprintf(stderr, "\nThe receive portion of this program sets the Ethernet");
- fprintf(stderr, "\ndriver to use a multicast address, then waits for the");
- fprintf(stderr, "\n10000 - 1500 byte packets or times out after 30 seconds.\n");
- fprintf(stderr, "\n\nUsing SAP address %d.\n", TESTSAP);
-
- }
-
- UInt32 GetYesNoOption(void)
- {
- UInt32 result;
- char selection[32];
- Boolean done;
-
- fprintf(stdout, "\n Enter Y - To accept option");
- fprintf(stdout, "\n Enter N - To decline option");
- fprintf(stdout, "\n Enter Q - To quit");
- fprintf(stdout, "\nYour selection -> ");
- fflush(stdout);
- done = false;
-
- do
- {
- scanf("%s", selection);
- switch (selection[0])
- {
- case 'y':
- case 'Y':
- result = kAcceptOption;
- done = true;
- break;
-
- case 'n':
- case 'N':
- result = kDeclineOption;
- done = true;
- break;
-
- case 'q':
- case 'Q':
- result = kQuitTest;
- done = true;
- break;
-
- default:
- fprintf(stdout, "\nInvalid entry - %c, try again -> ", selection);
- fflush(stdout);
- break;
-
- }
- } while (!done);
-
- fflush (stdout);
- return result;
- }
-
-
- UInt32 GetUserOption(void)
- {
- UInt32 result;
- char selection[32];
- Boolean done;
-
- fprintf(stdout, "\nSelect the type of test to run");
- fprintf(stdout, "\nMake sure that the receive program is already launched");
- fprintf(stdout, "\n Enter S - Send test packets");
- fprintf(stdout, "\n Enter R - Receive test packets");
- fprintf(stdout, "\n Enter q - quit");
- fprintf(stdout, "\nYour selection -> ");
- fflush(stdout);
- done = false;
-
- do
- {
- scanf("%s", selection);
- switch (selection[0])
- {
- case 'r':
- case 'R':
- result = kReceiveTest;
- done = true;
- break;
-
- case 's':
- case 'S':
- result = kSendTest;
- done = true;
- break;
-
- case 'q':
- case 'Q':
- result = kQuitTest;
- done = true;
- break;
-
- default:
- fprintf(stdout, "\nInvalid entry - %c, try again -> ", selection);
- fflush(stdout);
- break;
-
- }
- } while (!done);
-
- fflush (stdout);
- return result;
- }
-
- /*
- CanDoMDATAMode gets the endpoint info and checks whether the T_CAN_SUPPORT_MDATA bit is
- set in the endpoint info flag field and returns true if so, false otherwise.
- */
- Boolean CanDoMDATAMode(EndpointRef ep)
- {
- TEndpointInfo info;
- OSStatus err;
- Boolean result;
-
- err = OTGetEndpointInfo(ep, &info);
- if (err != kOTNoError)
- result = false;
- else if (info.flags & T_CAN_SUPPORT_MDATA)
- result = true; // this also means that the src addr info is in the info record
- else
- result = false;
-
- return result;
- }
-
-
- void DoOTLLCWriteTest(void)
- {
- OSStatus osstatus;
- UInt32 numMemErrs, last250;
- UInt32 lastFlowErrPacketNum;
- UInt32 timer;
- time_t t1, t2, t3;
- UInt16 rawModeOffset = 0;
- Boolean callDoIdle;
-
-
- osstatus = DoBind();
-
- OTMemzero(&gPacket, sizeof(gPacket)); // zero out the global packet buffer structure
-
- if (TstUseAckSendsFlag(gFlags))
- {
- osstatus = OTAckSends(gEndpoint);
- if (osstatus != kOTNoError)
- {
- fprintf (stdout, "\n Error turning AckSends on - error %ld", osstatus);
- ClrUseAckSendsFlag(gFlags);
- gNumFore = gNumBack = 0;
- }
- }
-
- if (TstUseRawModeFlag(gFlags))
- {
- if (CanDoMDATAMode(gEndpoint) && (DATASIZE <= 1500))
- {
- osstatus = DoNegotiateRawModeOption(gEndpoint, kOTRawRcvOn, &gTemplateType);
- if (osstatus == kOTNoError)
- {
- SetRawModeFlag(gFlags);
- /* if rawmode is on then we want to offset the data
- * an additional 17 bytes and set the header info
- * ourselves.
- * note that 17 bytes constitutes the 6 byte dAddr, 6 byte sAddr
- * 2 byte length field, 1 byte ssap, 1 byte dsap and 1 byte control byte
-
- * Note that even if the DSAP is not 0xAA, we go ahead and stuff the 5 bytes
- * following the control byte, with whatever SNAP values have been defined.
- */
- gPacket.rawModeOffset = 17;
- // check is we are doing SNAP
- if (TESTSAP == 0xAA)
- gPacket.rawModeOffset += 5;
- fprintf (stdout, "\n raw mode option enabled");
- }
- else
- {
- // if the option failed, then we don't use it'
- fprintf (stdout, "\nError negotiating raw mode option");
- // reset the status result.
- osstatus = kOTNoError;
- }
- }
- else
- fprintf (stdout, "\nYou need a later version of OT which supports the MDataMode option");
- }
-
- #if __ASYNCSEND__
- if (osstatus == kOTNoError)
- {
- osstatus = OTSetAsynchronous(gEndpoint);
- if (osstatus != kOTNoError)
- {
- fprintf(stderr, "\n\nError making endpoint asynchronous!");
- fprintf(stderr, "\nOTSetAsynchronous returned %d\n", osstatus);
- }
- } // now ready to handle async events
- #endif
-
- if (osstatus == kOTNoError)
- {
- // set up the first 18 bytes past the control byte for non SNAP LLC endpoint or
- // past the SNAP header for a SNAP endpoint, so that we can recognize it
- OTStrCopy((char*)&gPacket.data[gPacket.rawModeOffset], "begin data section");
-
- // set up some specific bytes in the data buffer that begins at the same point
- // relative to the LLC or SNAP header
- gPacket.data[DATAOFFSET + gPacket.rawModeOffset] = 0;
- gPacket.data[DATAOFFSET + 1 + gPacket.rawModeOffset] = 0;
- OTStrCopy((char*)&gPacket.data[DATAOFFSET+2 + gPacket.rawModeOffset], "end of data section");
-
- gPacket.unitdata.udata.buf = (UInt8*)gPacket.data;
-
- if (TstRawModeFlag(gFlags))
- gPacket.unitdata.udata.len = DATASIZE + 14;
- else
- {
- // the DATASIZE setting represents the total size of the packet
- // following the ethernet header. If we are not doing a rawmode send
- // then we need to account for the fact that part of the data area
- // will be used by OT to place the SSAP, DSAP, and Control byte. If
- // we are sending a SNAP packet, then we have to account for the 5
- // additional bytes of the SNAP header. Otherwise if the unidata.data.len
- // field were set to the full size of 1500, the packet would not be sent
- // since OT would think it was trying to send a 1503 or 1508 byte
- // ethernet packet (not including the ethernet header).
-
- // By doing this, we can process the packet using either a raw data or
- // regular ethernet endpoint as the receiver.
-
- if (TESTSAP == 0xAA)
- gPacket.unitdata.udata.len = DATASIZE - 8;
- else
- gPacket.unitdata.udata.len = DATASIZE - 3;
- }
-
- gPacket.unitdata.opt.len = 0;
- gPacket.unitdata.opt.buf = NULL;
-
- if (TstRawModeFlag(gFlags) == false)
- {
- // set up the destination addresss
- gPacket.dAddr.fAddrFamily = AF_8022;
-
- gPacket.dAddr.fHWAddr[0] = MCASTADDR0;
- gPacket.dAddr.fHWAddr[1] = MCASTADDR1;
- gPacket.dAddr.fHWAddr[2] = MCASTADDR2;
- gPacket.dAddr.fHWAddr[3] = MCASTADDR3;
- gPacket.dAddr.fHWAddr[4] = MCASTADDR4;
- gPacket.dAddr.fHWAddr[5] = MCASTADDR5;
-
- gPacket.dAddr.fSAP = TESTSAP;
-
- gPacket.unitdata.addr.buf = (UInt8*)&gPacket.dAddr;
- if (TESTSAP == 0xAA)
- {
- gPacket.dAddr.fSNAP[0] = MYSNAP0;
- gPacket.dAddr.fSNAP[1] = MYSNAP1;
- gPacket.dAddr.fSNAP[2] = MYSNAP2;
- gPacket.dAddr.fSNAP[3] = MYSNAP3;
- gPacket.dAddr.fSNAP[4] = MYSNAP4;
-
- gPacket.unitdata.addr.len = k8022SNAPAddressLength;
- }
- else
- gPacket.unitdata.addr.len = k8022BasicAddressLength;
-
- }
- else
- {
- // set up for a rawmode send data call
- gPacket.data[0] = MCASTADDR0;
- gPacket.data[1] = MCASTADDR1;
- gPacket.data[2] = MCASTADDR2;
- gPacket.data[3] = MCASTADDR3;
- gPacket.data[4] = MCASTADDR4;
- gPacket.data[5] = MCASTADDR5;
- // set the packet len field
- gPacket.data[12] = DATASIZE >> 8;
- gPacket.data[13] = DATASIZE & 0xFF;
- // set the dsap, ssap, and control byte fields.
- gPacket.data[14] = TESTSAP; // set DSAP
- gPacket.data[15] = TESTSAP; // set SSAP
- gPacket.data[16] = 0x03; // set control byte
-
- if (TESTSAP == 0xAA)
- {
- // set up the SNAP Addr
- gPacket.data[17] = MYSNAP0;
- gPacket.data[18] = MYSNAP1;
- gPacket.data[19] = MYSNAP2;
- gPacket.data[20] = MYSNAP3;
- gPacket.data[21] = MYSNAP4;
- }
-
- gPacket.unitdata.addr.buf = nil;
- // don't want to set the destination address since we've already
- // done so in the data
-
- // the following line is required for OT 1.2 and greater
- // where there is a bug with how OT deals with mentat template
- // based drivers, such that in rawmode, the total packet size -
- // header + data is limited to 1500 bytes. By using the following
- // line, OT will not check for this limitation and will go ahead
- // and send an MDATA message.
-
- gPacket.unitdata.addr.len = 0xFFFFFFFFL;
- // magic constant for M_DATA mode
-
- }
-
-
- ClrFlowClrFlag(gFlags); // clear the flag that indicates that a T_GODATA event occurred
- // we do this because a race condition might occur when we make the
- // the OTSndUData call, a flowerr may occur, but get cleared by the time
- // we actually check the osstatus field
-
- fprintf (stdout, "\n starting write of %ld llc packets of %ld bytes\n", (long)SENDCOUNT, (long)DATASIZE);
- fflush(stdout);
- t1 = clock ();
-
- gDone = false;
- gPacket.i = 0;
- numMemErrs = last250 = 0;
- lastFlowErrPacketNum = 0;
- timer = 0;
- callDoIdle = false;
-
- // set the flag that will tell us to send a packet at system task time so that
- // we can send the initial packet
- SetSysTaskSendFlag(gFlags);
-
- while (!gDone && !gAbort)
- {
- if (TstSysTaskSendFlag(gFlags))
- {
- if (DoSendPacket(gEndpoint) == true)
- {
- gNumFore++;
- }
- }
-
- if (gNumMemErrs)
- {
- if (numMemErrs != gNumMemErrs)
- {
- numMemErrs = gNumMemErrs;
-
- fprintf(stderr, "\nkENOMEMErr %ld.", gPacket.i);
- callDoIdle = true;
- }
- }
-
- #if 0 // the following code really affect the performance of this tool
- // and can consume over 95 percent of the processing time of this tool
- // on a fast system.
- n = gPacket.i / 250;
- if (n > last250)
- {
- fprintf(stderr, "%d ", n * 250);
- fflush(stderr);
- last250 = n;
-
- }
- #endif
-
- timer++;
- if (timer > gTimerThreshold)
- {
- callDoIdle = true;
- }
-
- if (gPacket.lastFlowErrPacketNum != 0)
- {
- if (lastFlowErrPacketNum != gPacket.lastFlowErrPacketNum)
- {
- fprintf(stderr, "\nflow error occurred while sending packet %d.", gPacket.lastFlowErrPacketNum);
- lastFlowErrPacketNum = gPacket.lastFlowErrPacketNum;
- }
- }
-
- // check if we are flow controlled or if it's time to call WNE and call it.
- if ((callDoIdle == true) || TstFlowErrFlag(gFlags))
- {
- CallWNE();
- callDoIdle = false;
- timer = 0;
- }
-
- } // end while loop sending data
-
- fflush(stderr);
-
- t2 = clock();
- t3 = t2 - t1;
- fprintf (stdout, "\nCompleted sending %ld llc packets.", (long)gPacket.i);
- fprintf (stdout, "\nTime start = %ld, time end = %ld, time taken %ld seconds.",
- t1, t2, (long)t3/CLOCKS_PER_SEC);
- fprintf (stdout, "\nPackets per second = %ld, bytes/second = %ld.",
- ((long)gPacket.i*CLOCKS_PER_SEC)/t3, ((long)gPacket.i*DATASIZE*CLOCKS_PER_SEC)/t3);
-
- fprintf (stdout, "\n Press the mouse to unbind the endpoint");
-
- if (TstUseAckSendsFlag(gFlags) == true)
- {
- fprintf (stdout, "\nThe number of packets sent from the while loop - %ld", gNumFore);
- fprintf (stdout, "\nThe number of packets sent from the handler - %ld", gNumBack);
- }
-
- fflush(stdout);
-
- while (!Button())
- MyIdle();
-
-
- } // end if bind successful
-
- #if __ASYNCSEND__
- if (TstEPBoundFlag(gFlags))
- {
- OTSetSynchronous(gEndpoint);
- OTUnbind(gEndpoint);
- }
- #endif
-
- }
-
- Boolean DoSendPacket(EndpointRef ep)
- {
- OSStatus osstatus;
- Boolean didEnter;
-
- // check to see if we have already entered this function.
- // we only want to enter into it once whether at system task time or from the
- // handler
- if (OTAtomicSetBit(&gFlag1, kInSendPacketBit))
- return false;
-
- // call OTenterNotifier so that the notifier is not entered while we are in the following
- // section of code. In this way we protect ourselves from race conditions that could
- // happen - for example if a flowErr occured, but was cleared before we set the flowErr
- // flag, this would be a problem since we would never receive notification that flow
- // control was lifted.
-
- didEnter = OTEnterNotifier(ep);
-
- if (gDone == false)
- {
- // we already assume that the packet is ready to send
- osstatus = OTSndUData(gEndpoint, &gPacket.unitdata);
- }
-
- switch (osstatus)
- {
- case kENOMEMErr:
- gNumMemErrs++;
- break;
-
- case kOTNoError: // send was successful
- gPacket.i++;
-
- if (gPacket.i >= SENDCOUNT)
- gDone = true;
- else
- {
- // increment the counter in the packet
- gPacket.data[DATAOFFSET+0+gPacket.rawModeOffset] = gPacket.i >> 8;
- gPacket.data[DATAOFFSET+1+gPacket.rawModeOffset] = gPacket.i;
-
- }
- break;
-
- case kOTFlowErr:
- SetFlowErrFlag(gFlags); // a T_GODATA did not just come in
- ClrSysTaskSendFlag(gFlags); // clear the flag that we check to send a packet
- gPacket.lastFlowErrPacketNum = gPacket.i; // save the packet number on which the flow err occured
- break;
-
- default:
- DoValueBreak(osstatus, "Unknown error occurred in DoSendPacket #;");
- gDone = true;
- ClrSysTaskSendFlag(gFlags);
- break;
- }
-
- if (didEnter == true)
- OTLeaveNotifier(ep);
-
- OTAtomicClearBit(&gFlag1, kInSendPacketBit);
- return true;
- }
-
- void DoOTLLCReadTest(void)
- {
- OSStatus osstatus;
- long timer;
-
- gBuffer = (UInt8*)NewPtr(DATASIZE + 2* DATASLOP); // allocate the data buffer + some slop
- if (gBuffer)
- osstatus = DoBind();
- else
- {
- osstatus = memFullErr;
- return;
- }
-
- gBackToBackPackets = 0;
- gInOrder = 0;
- gOutOfOrder = 0;
- gCounter = 0;
- gPacketsRead = 0;
- gNumDataEvents = 0;
- gReadErrors = 0;
- gNumMemErrs = 0;
- gDone = false;
-
- if (osstatus == kOTNoError)
- {
- osstatus = DoAddMulticast(gEndpoint, gmcAddr);
- }
-
- if (osstatus == kOTNoError)
- {
- if (TstUseRawModeFlag(gFlags))
- {
- osstatus = DoNegotiateRawModeOption(gEndpoint, kOTRawRcvOn, &gTemplateType);
- if (osstatus == kOTNoError)
- {
- SetRawModeFlag(gFlags);
- }
- else
- {
- // if the option failed, then we don't use it'
- fprintf (stdout, "\nError negotiating raw mode option");
- // reset the status result.
- osstatus = kOTNoError;
- }
- }
- }
-
- #ifdef __ASYNCSEND__
- if (osstatus == kOTNoError)
- {
- osstatus = OTSetAsynchronous(gEndpoint);
- if (osstatus != kOTNoError)
- {
- fprintf(stderr, "\n\nError making endpoint asynchronous!");
- fprintf(stderr, "\nOTSetAsynchronous returned %d\n", osstatus);
- }
- } // now ready to handle async events
- #endif
-
- if (osstatus == kOTNoError)
- {
- gAbort = false;
- SetWantDataFlag(gFlags);
-
- fprintf (stdout, "\nStarting Read test - will terminate in %d seconds", TIMEOUT);
- fprintf (stdout, "\nor as soon as the trigger packet is received.");
- fprintf (stdout, "\nYou may use Command-Q to quit the program entirely.");
- fprintf (stdout, "\nYou may also use Command-A to terminate this test.\n");
- fprintf (stdout, "\nStarting Read");
- fflush(stdout);
-
- timer = TickCount() + TIMEOUT * 60;
- // loop until timer is less than TickCount or until the endtime value gets set
-
- while ((timer > TickCount()) && (gDone == false) && (gAbort == false))
- {
- // allow the user to exit the timer loop by
- CallWNE();
- }
-
-
-
- }
-
- OTSetSynchronous(gEndpoint);
-
- if (TstMCastActiveFlag(gFlags))
- DoRemoveMulticast(gEndpoint, gmcAddr);
-
-
- if (osstatus == kOTNoError)
- {
- fprintf (stdout, "\n\nBufferReadCount = %ld", gPacketsRead);
- fprintf (stdout, "\nInOrder = %ld\n", gInOrder);
- fprintf (stdout, "\nOutofOrder = %ld\n", gOutOfOrder);
- fprintf (stdout, "\nlast packet read was = %ld\n", gCounter);
- fprintf (stdout, "\nNumber of data events was = %ld\n", gNumDataEvents);
- fprintf (stdout, "\nNumber of read errors was = %ld\n", gReadErrors);
- fprintf (stdout, "\nNumber of back to back packets was = %ld\n", gBackToBackPackets);
- fflush(stdout);
- }
-
- if (TstEPBoundFlag(gFlags))
- OTUnbind(gEndpoint);
-
- if (gBuffer)
- DisposePtr((Ptr)gBuffer);
-
- }
-
- OSStatus DoReadPacket(EndpointRef ep, UInt8 *mainBuffer)
- {
- TUnitData unitdata;
- struct T8022Address dAddr;
- OTFlags otFlags;
- OSStatus result;
-
- unitdata.addr.maxlen = sizeof(dAddr);
- unitdata.addr.buf = (UInt8*)&dAddr;
- unitdata.udata.buf = mainBuffer;
- unitdata.udata.maxlen = DATASIZE + DATASLOP;
- unitdata.opt.maxlen = 0;
-
- result = OTRcvUData(ep, &unitdata, &otFlags);
- return result;
- }
-
- pascal void LLCEventHandler(void* ref, OTEventCode event, OTResult result, void* cookie)
- {
- #pragma unused(ref,cookie)
- OSStatus osstatus;
- UInt8 *bufferToUse;
- UInt32 lcounter, offset;
- Boolean firstTimeFlag;
-
- gstatus = result;
- switch (event)
- {
- case T_MEMORYRELEASED:
- if (DoSendPacket(gEndpoint) == false)
- SetSysTaskSendFlag(gFlags);
- else
- {
- ClrSysTaskSendFlag(gFlags);
- gNumBack++;
- }
- break;
-
- case T_OPTMGMTCOMPLETE:
- ClrWaitOptMgmtFlag(gFlags);
- break;
-
- case T_BINDCOMPLETE:
- ClrStillBindFlag(gFlags);
- break;
-
- case T_UNBINDCOMPLETE:
- break;
-
- case T_GODATA:
- SetFlowClrFlag(gFlags); // indicate that the flow data problem has now cleared.
- SetSysTaskSendFlag(gFlags);
- break;
-
- case T_DATA:
- gNumDataEvents++;
- if (TstWantDataFlag(gFlags))
- bufferToUse = gBuffer;
- else
- bufferToUse = gDummyBuffer;
-
- // initialize variables as we enter while loop
- osstatus = kOTNoError;
- firstTimeFlag = true;
-
- while ((osstatus == kOTNoError) && (!gDone))
- {
- osstatus = DoReadPacket(gEndpoint, bufferToUse);
-
- if (firstTimeFlag == true)
- // this is the first time through this loop
- // for this call to the handler
- firstTimeFlag = false;
- else
- // increment the counter to indicate that there was a packet to
- // handle after reading the previous packet
- gBackToBackPackets++;
-
- if (osstatus != kOTNoDataErr)
- {
- if (osstatus < 0)
- gReadErrors++;
- else
- gPacketsRead++;
- }
-
- if (TstWantDataFlag(gFlags) && (osstatus == kOTNoError))
- {
- if (TstRawModeFlag(gFlags))
- {
- // if rawmode is on then we want to account for
- // the additional 17 bytes which will be at the
- // beginning of the packet.
- offset = 17;
- if (TESTSAP == 0xAA)
- {
- offset += 5; // account for the SNAP header
- }
-
- // check if the template is a mentat template and
- // adjust the offset to account for the additional
- // bytes that the template prepends to the ethernet
- // packet.
- if (gTemplateType == kMentatTemplate)
- offset += sizeof(dl_recv_status_t);
- }
- else
- offset = 0;
-
- lcounter = gBuffer[DATAOFFSET + offset +0] << 8;
- lcounter |= gBuffer[DATAOFFSET + offset +1];
- if (lcounter >= TRIGGEREND)
- {
- gDone = true; // we can bail now.
- }
- else
- {
- if (lcounter == gCounter)
- gInOrder++;
- else
- gOutOfOrder++;
-
- gCounter = lcounter + 1; // prepare gCounter for next incoming packet to compare
- }
- }
- }
- break;
-
- default:
- DoValueBreak(event, "Unknown event occurred # ;g");
- break;
-
-
- } /* end switch on event */
- }
-
- /*******************************************************************************
- ** CallWNE is implemented to call WaitNextEvent to check for the Command-Q key
- ** sequence. When this happens, then the gdone flag is set to true
- ********************************************************************************/
-
- void CallWNE(void)
- {
- EventRecord event;
- char key;
-
- if (!WaitNextEvent(everyEvent, &event, 15, nil))
- event.what = nullEvent;
-
- switch (event.what)
- {
-
-
- case nullEvent:
- case mouseDown:
- case activateEvt:
- case updateEvt:
- case kHighLevelEvent:
- case osEvt:
- case diskEvt:
- break;
-
- case autoKey:
- case keyDown:
- key = event.message & charCodeMask;
- switch (key)
- {
- case 'q':
- case 'Q':
- if (event.modifiers & cmdKey)
- gDone = true;
- break;
-
- case 'a':
- case 'A':
- if (event.modifiers & cmdKey)
- gAbort = true;
- break;
- }
- break;
-
- }
-
- }
-
- void MyIdle(void)
- {
- EventRecord event;
- OSErr err;
-
- err = WaitNextEvent(everyEvent, &event, 15 + gNumMemErrs * 5, nil);
- }
-
- void main (void)
- {
- OSStatus osstatus = noErr;
- UInt32 selection;
- char drvrname[64];
- Boolean done = false;
-
- WriteApplIntro();
- gFlags = 0;
- if (osstatus = InitOpenTransport())
- {
- fprintf(stderr, "\n\nOpen Transport is not installed!\n");
- fprintf(stderr, "\nBye Bye.\n");
- }
- else
- {
- SetOTActiveFlag(gFlags); // indicate that OT is active
-
- gDummyBuffer = (UInt8*)NewPtr(DATASIZE + 2 * DATASLOP);
- if (gDummyBuffer == NULL)
- osstatus = memFullErr;
- }
-
- PrintAppleTalkPortName();
-
- while (done == false)
- {
- osstatus = OTSetMemoryLimits(10240000, 0);
- if (osstatus != kOTNoError)
- {
- fprintf(stderr, "\n OTSetMemoryLimits returned %d\n", osstatus);
- osstatus = kOTNoError;
- }
-
- if (osstatus != kOTNoError)
- {
- done = true;
- break;
- }
-
- ListEnetDrivers();
- GetDriverName(drvrname);
-
- // open the default ethernet endpoint
- gEndpoint = OTOpenEndpoint(OTCreateConfiguration(drvrname), (OTOpenFlags)NULL, NULL, &osstatus);
- if (osstatus != kOTNoError)
- {
- fprintf(stderr, "\n\nError opening Ethernet endpoint!");
- fprintf(stderr, "\nOTOpenEndpoint returned %d\n", osstatus);
- fprintf(stderr, "\nBye Bye.\n");
- done = true;
- }
- else
- SetEPActiveFlag(gFlags); // indicate that the endpoint is opened
-
- if (osstatus == kOTNoError)
- {
- osstatus = OTInstallNotifier(gEndpoint, LLCEventHandler, NULL);
- if (osstatus != kOTNoError)
- {
- fprintf(stderr, "\n\nError installing notifier!");
- fprintf(stderr, "\nOTInstallNotifier returned %d\n", osstatus);
- }
- } // now ready to handle async events
-
- if (osstatus == kOTNoError)
- {
- // ask whether to use the rawmode option or not
- fprintf(stdout, "\nDo you want to use the raw mode option?");
- selection = GetYesNoOption();
- if (selection == kQuitTest)
- {
- fprintf(stderr, "\n\nBye-Bye!");
- osstatus = -1;
- done = true;
- }
- else if (selection == kAcceptOption)
- SetUseRawModeFlag(gFlags);
- else if (selection == kDeclineOption)
- ClrUseRawModeFlag(gFlags);
-
- }
-
- if (osstatus == kOTNoError)
- {
-
- // what does the user want to do
- selection = GetUserOption();
-
- switch (selection)
- {
- case kSendTest:
- fprintf(stdout, "\nDo you want to turn on AckSends?");
- selection = GetYesNoOption();
- if (selection == kQuitTest)
- {
- fprintf(stderr, "\n\nBye-Bye!");
- done = true;
- break;
- }
- else if (selection == kAcceptOption)
- {
- SetUseAckSendsFlag(gFlags);
- }
- else if (selection == kDeclineOption)
- {
- ClrUseAckSendsFlag(gFlags);
- SetTimerThreshold();
- }
-
- // pause until the user clicks the mouse button
- fprintf(stderr, "Click Mouse to start test\n");
- while (!Button());
- DoOTLLCWriteTest();
- break;
-
- case kReceiveTest:
- // pause until the user clicks the mouse button
- fprintf(stderr, "\n\nClick Mouse to start test\n");
- while (!Button());
-
- DoOTLLCReadTest();
- break;
-
- case kQuitTest:
- default:
- fprintf(stderr, "\n\nBye-Bye!");
- done = true;
- break;
- }
- }
-
- if (TstEPActiveFlag(gFlags))
- {
- // force endpoint to be synchronous
- OTSetSynchronous(gEndpoint);
- OTCloseProvider(gEndpoint);
- }
-
- if (done == false)
- {
- fprintf(stdout, "\n\nDo you want to repeat the test?");
- selection = GetYesNoOption();
-
- if (selection != kAcceptOption)
- done = true;
- }
- }
-
- if (gDummyBuffer)
- DisposePtr((Ptr)gDummyBuffer);
-
- OTSetMemoryLimits(0, 0);
-
- if (TstOTActiveFlag(gFlags))
- CloseOpenTransport();
-
- fprintf(stderr, "\nProgram ended");
- }
-
- void DoValueBreak(long value, const char* message)
- {
- static short sDoErrorBreak = 0;
-
- {
- Str255 s,
- n = "\p";
-
- s[0] = strlen(message);
- BlockMoveData(message,&s[1],s[0]);
- if (value < 0)
- {
- s[0] += 1;
- s[s[0]] = '-';
- value = -value;
- }
- while (value)
- {
- if (n[0])
- BlockMoveData(&n[1],&n[2],n[0]);
- n[0]++;
- n[1] = 48 + (value % 10);
- value /= 10;
- }
- BlockMoveData(&n[1],&s[s[0]+1],n[0]);
- s[0] += n[0];
-
- sDoErrorBreak++;
- {
- short cnt = sDoErrorBreak;
-
- s[0]++;
- s[s[0]] = ',';
- s[0]++;
- s[s[0]] = ' ';
- n[0] = 0;
- while (cnt)
- {
- if (n[0])
- BlockMoveData(&n[1],&n[2],n[0]);
- n[0]++;
- n[1] = 48 + (cnt % 10);
- cnt /= 10;
- }
- BlockMoveData(&n[1],&s[s[0]+1],n[0]);
- s[0] += n[0];
- }
- DebugStr(s);
- }
- }
-
- void GetDriverName(char *name)
- {
- fprintf(stdout, "\nEnter the driver name to use");
- fprintf(stdout, "\nEnter an invalid driver name to quit");
- fprintf(stdout, "\n : ");
- while (true)
- {
- gets(name);
- if (*name != 0)
- break;
- }
- }
-
- void SetTimerThreshold(void)
- {
- char chr, str[256];
- size_t len, i;
- Boolean done = false;
-
- while (done == false)
- {
- fprintf(stdout, "\n Enter the timer threshold");
- fprintf(stdout, "\n This is the number of times that the write loop loops before calling");
- fprintf(stdout, "\n WaitNextEvent. Enter a value of 10000 to never call WNE.");
- fprintf(stdout, "\n Enter a value of 100 to call WNE every 100 packets.\n");
- while (true)
- {
- gets(str);
- if (*str != 0)
- break;
- }
-
- gTimerThreshold = 0;
- len = strlen(str);
-
- for (i = 0; i < len; i++)
- {
- chr = str[i];
- if ((chr >= '0') && (chr <= '9'))
- gTimerThreshold = gTimerThreshold*10 + chr - '0';
- }
-
- if (gTimerThreshold != 0)
- {
- done = true;
- fprintf(stdout, "\n The timer threshold is set at %ld\n\n", gTimerThreshold);
- fflush(stdout);
- }
- }
- }
-
- /*
- The following routine prints the name of the port currently being used by AppleTalk
- If AppleTalk is using Ethernet, then the fPortName field could be used in the
- OpenEndpoint call to open an ethernet endpoint on the same hardware port as AppleTalk
- */
- void PrintAppleTalkPortName(void)
- {
- ATSvcRef atref;
- OSStatus err;
- OTPortRef portref;
- OTPortRecord portrecord;
- TEndpointInfo info;
-
- atref = OTOpenEndpoint(OTCreateConfiguration(kDDPName), 0, &info, &err);
-
- if (err == kOTNoError)
- {
- portref = OTGetProviderPortRef(atref);
- if (portref != nil)
- {
- if (OTFindPortByRef(&portrecord, portref) == true)
- {
- // fprintf(stderr, "\n Appletalk port name is %s", portrecord.fPortName);
- portref = portrecord.fChildPorts[0];
- if (OTFindPortByRef(&portrecord, portref) == true)
- fprintf(stdout, "\n Appletalk child port name is %s", portrecord.fPortName);
- else
- fprintf(stdout, "\n Appletalk child port record could not be found using PortRef %lX", portref);
- }
- else
- fprintf(stdout, "\n Appletalk port record could not be found using PortRef %lX", portref);
- }
- else
- fprintf(stdout, "\n OTGetProviderPortRef returned nil result");
-
- OTCloseProvider(atref);
- }
- else
- fprintf(stdout, "\n OTOpenAppleTalkServices returned error %d", err);
-
-
- }
-
- void ListEnetDrivers(void)
- {
- OTPortRecord portRecord;
- Boolean foundAPort;
- UInt32 index;
- Str255 userFriendlyName;
-
- fprintf(stdout, "\n The list of drivers present is:\n");
- index = 0;
- // iterate thru each OT port record for ethernet ports.
- while (foundAPort = OTGetIndexedPort(&portRecord,index))
- {
- if ((portRecord.fCapabilities & kOTPortIsDLPI) &&
- (portRecord.fCapabilities & kOTPortIsTPI) &&
- (kOTEthernetDevice == OTGetDeviceTypeFromPortRef(portRecord.fRef)))
- {
- OTGetUserPortNameFromPortRef(portRecord.fRef, userFriendlyName);
- fprintf(stdout, "\n Driver name - %s, ", portRecord.fPortName);
- fprintf(stdout, "user readable name is - %#s", userFriendlyName);
-
- }
- index++;
- }
- fprintf(stdout, "\n");
-
- }
-